/*
 * Postmore - a pop3 supported mailing list server;
 * Copyright (C) 2010 Peng Lei, pyp125@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 
 * details.
 *
 * You should have received a copy of the GNU Public License along with this
 * program. If not, see http://www.gnu.org/licenses/.
*/

#include "utilities.h"

/* INI style configuration reading functions. 2010 August 9th, first version of libcfg. */

char* l_trim(char* s)
{
	char* s2=s;
	while(s2[0]==' ' || s2[0]=='\t')
		s2+=1;
	strcpy(s,s2);
	return s;
};

int cfg_init(const char* p)
{
	_cfg_lock=0;
	if(!p)
		return -1;
	if(!(_f_cfg=fopen(p,"r")))
		return -1;
	return 0;
}

int cfg_get(const char* s,const char* n,void* o)
{
	while(_cfg_lock)
		;
	/* Lock the file; */
	_cfg_lock=1;
	char lstr[LMAX];
	char sstr[SMAX];
	char nstr[NMAX];
	char ostr[VMAX];
	int f=0;	/* flag: found; */
	bzero(nstr,sizeof(nstr));
	bzero(sstr,sizeof(sstr));
	bzero(lstr,sizeof(lstr));
	sprintf(sstr,SECTION,s);
	while(fgets(lstr,sizeof(lstr),_f_cfg))
	{
		l_trim(lstr);
		if(lstr[0]=='#')
			continue;
		if(!strncmp(lstr,sstr,strlen(sstr)))	/* Found; */
		{
			f=1;
			continue;
		}
		if(f)
		{
			bzero(nstr,sizeof(nstr));
			bzero(ostr,sizeof(ostr));
			/* Wrong format, return -2; */
			if(sscanf(lstr,FORMAT,nstr,ostr)<2)
			{
				rewind(_f_cfg);
				/* Unlock; */
				_cfg_lock=0;
				return -2;
			}
			if(!strncmp(nstr,n,strlen(n)))
			{
				/* String processing; */
				if(ostr[0]=='"')
				{
					int l=strlen(ostr)-1;
					ostr[l]='\0';
					char* ocp=strstr(ostr,"\"")+1;
					strcpy(o,ocp);
				}
				else 
				{
					/* Float number; */
					if(strstr(ostr,"."))
					{
						float oft;
						sscanf(ostr,"%f",&oft);
						(*((float*)o))=oft;
					}
					else 
					{
						/* Integer; */
						int oit;
						sscanf(ostr,"%d",&oit);
						(*((int*)o))=oit;
					}
					
				}
				
				rewind(_f_cfg);
				/* Unlock; */
				_cfg_lock=0;
				return 0;
			}
		}
		
		bzero(lstr,sizeof(lstr));
	}
	rewind(_f_cfg);
	/* No found, unlock the file and return -1; */
	_cfg_lock=0;
	return -1;
}

int cfg_exit()
{
	if(fclose(_f_cfg)!=0)
		return -1;
	return 0;
}

/* Log recording functions. */
int pmlog_init(const char* p)
{
	if(!p)
		return -1;
	strcpy(_p_log,p);
	return 0;
}

int pmlog(const char* p)
{
	FILE* _f_log;
	if(!(_f_log=fopen(_p_log,"a+")))
		return -1;
	time_t t;
	time(&t);
	if(fprintf(_f_log,LOG_FM,ctime(&t),p)<0)
	   return -1;
	 fclose(_f_log);
	return 0;
}

/* Linked list operations; */
NODE* list_create(void* data,size_t size_in)
{
	NODE* new=(NODE*)malloc(sizeof(struct _node));
	new->size=size_in;
	new->data=malloc(size_in);
	memcpy(new->data,data,size_in);
	new->next=NULL;
	return new;
}

int list_add(NODE* first,void* toadd,size_t size)
{
	if(!toadd)
		return -2;
	if(!first)
		return -1;
	NODE* next=first;
	while(next->next)
		next=next->next;
	NODE* new=list_create(toadd,size);
	next->next=new;
	return 0;
}

int list_del(NODE* first,void* todel,size_t size)
{
	NODE *pre,*next;
	if(!todel)
		return -2;
	/* Delete the first node; */
	if(!memcmp(first->data,todel,size))
	{
		/* If the list only has one element, clear it and return 1;*/
		if(!first->next)
		{
			list_clear(first);
			return 1;
		}
		pre=first;
		next=first->next;
		while(next)
		{
			list_set(pre,next->data,next->size);
			if(!next->next)
				pre->next=0;
			pre=next;
			next=next->next;
		}
		free(pre->data);
		free(pre);
		return 0;
	}
	pre=first;
	next=first->next;
	while(next)
	{
		/* Found; */
		if(!memcmp(next->data,todel,size))
		{
			pre->next=next->next;
			free(next->data);
			free(next);
			return 0;
		}
		pre=next;
		next=next->next;
	}
	/* Not found; */
	return -1;
}

int list_set(NODE* node, void* toset, size_t size)
{
	node->data=realloc(node->data,size);
	memcpy(node->data,toset,size);
	node->size=size;
	return 0;
}

void list_clear(NODE* first)
{
	NODE* next=first;
	while(first->next)
	{
		first=first->next;
		free(next->data);
		free(next);
		next=first;
	}
}

int base64(const char* src,char* dst)
{
	if(!src || !dst)
		return -1;
	/* base64 code; */
	char base64[65]={
		'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 
		'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 
		'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 
		'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/','='
	};
	char isrc[3], idst[4];
	int i, j, k;
	bzero(dst,sizeof(dst));
	for(i=0,j=0;i<strlen(src);i+=3,j+=4)
	{
		int i1=i+1;
		int i2=i+2;
		isrc[0]=src[i];
		isrc[1]=(sizeof(src)<=i1?0:src[i1]);
		isrc[2]=(sizeof(src)<=i2?0:src[i2]);
		idst[0]=(isrc[0]>>2)&0x3f;
		idst[1]=((isrc[0]<<4)|(isrc[1]>>4))&0x3f;
		idst[2]=((isrc[1]<<2)|(isrc[2]>>6))&0x3f;
		idst[3]=isrc[2]&0x3f;
		for(k=0;k<4;k++)
			dst[j+k]=idst[k]?base64[idst[k]]:'=';
	}
	
	return 0;
}